# geometry.XY -- Base class for floating point pairs
#
# Copyright (c) 2000, V.Kelson and M.Bakker
#

from math import sqrt
import geometry.xyz

class XY:
	"""Object for data pairs
	
	The XY class contains objects that have two floating point components,
	such as (x,y) or (qx,qy). A number of mathematical operations are
	defined for dealing with XY objects, such as adding XY objects, multiplying
	them with a scalar, and so on. The XY object is the standard object to
	pass around two floating points.
	"""
	def __init__(self,x,y):
		"""Constructor"""
		self.x = float(x)
		self.y = float(y)
	def __repr__(self):
		"""Representation"""
		return 'XY' + str((self.x,self.y))
	def __add__(self,b):
		""" Overloaded addition of two XY's or XY + scalar

		Format: a + b, where a is an XY object and b is
		either an XY object or a scalar"""
		if isinstance(b,XY):
			return XY(self.x+b.x,self.y+b.y)
		else:
			return XY(self.x,self.y+b)
	def __radd__(self,a):
		""" Overloaded right addition of scalar or XY and XY

		Format: a + b, where a is a scalar or an XY object and b is an XY object"""
		if isinstance(a,XY):
			return XY(self.x+a.x,self.y+a.y)
		else:
			return XY(self.x+a,self.y)
	def __sub__(self,pt):
		""" Overloaded subtraction of two XY's

		Format: a + b, where both a and b are XY objects"""
		assert isinstance(pt,XY)
		return XY(self.x-pt.x,self.y-pt.y)
	def __mul__(self,a):
		"""Overloaded multiplication by scalar a

		Returns an XY. Format: a * XY """
		f = float(a)
		return XY(f*self.x,f*self.y)
	def __rmul__(self,a):
		"""Overloaded right multiply by a scalar a

		Returns an XY. Format: XY * a """
		f = float(a)
		return XY(f*self.x,f*self.y)
	def __div__(self,a):
		"""Divides the object by a scalar.

		Returns an XY. Format: XY/a"""
		f = float(a)
		return XY(self.x/f,self.y/f)
	def __abs__(self):
		"""Returns the magnitude

		Returns a float"""
		return sqrt(self.x*self.x + self.y*self.y)
	def __complex__(self):
		"""Converts to complex

		Returns the object as a complex coordinate"""
		return complex(self.x,self.y)
	def tuple(self):
		"""Converts the object to a tuple

		Returns the object as tuple"""
		return (self.x,self.y)
	def distance2(self,pt):
		"""Returns the distance squared

		Returns the distance between self and pt as a float"""
		assert isinstance(pt,XY)
		return (pt.x-self.x)**2 + (pt.y-self.y)**2
	def lengthSquared(self):
		"""Returns the magnitude

		Returns the square of the magnitude (length) of the object as a float"""
		return (self.x**2 + self.y**2)
	def magnitude(self):
		"""Returns the magnitude

		Returns the magnitude (length) of the object as a float"""
		return sqrt(self.lengthSquared())
	def unitNormal(self):
		"""Returns the left-normal unit vector

		Returns the left-normal unit vector as an XY"""
		length = sqrt(self.x**2 + self.y**2)
		return XY(-self.y/length,self.x/length)
	def XYZ(self,z=0.0):
		"""Converts to an XYZ

		Returns an XYZ object; z is an optional argument"""
		return geometry.xyz.XYZ(self.x,self.y,z)

